feat(kona): execute NUT bundles at Karst fork activation#20157
Open
feat(kona): execute NUT bundles at Karst fork activation#20157
Conversation
Wiz Scan Summary
To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension. |
Codecov Report✅ All modified and coverable lines are covered by tests.
Additional details and impacted files@@ Coverage Diff @@
## develop #20157 +/- ##
===========================================
- Coverage 76.6% 66.3% -10.3%
===========================================
Files 691 55 -636
Lines 76081 4035 -72046
===========================================
- Hits 58298 2677 -55621
+ Misses 17639 1214 -16425
Partials 144 144
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
c38d430 to
0a41e7d
Compare
added 2 commits
April 20, 2026 17:01
Add build.rs that reads karst_nut_bundle.json at compile time and generates Rust code to construct the NutBundle. The derive pipeline now adds upgrade gas to the block gas limit at fork activation, matching op-node's gas accounting behavior.
Verifies that every fork with an embedded NUT bundle produces an activation block containing exactly the bundle's deposit transactions. Discovery uses forks.All + derive.UpgradeTransactions, so future forks with NUT bundles are covered automatically without test changes.
0a41e7d to
df9aabf
Compare
maurelian
commented
Apr 21, 2026
sebastianst
reviewed
Apr 21, 2026
941e15a to
caf98bb
Compare
added 3 commits
April 21, 2026 14:41
The Docker build context for kona images is scoped to rust/, so build.rs cannot reach op-core/nuts/bundles/ via ancestor walk and the kona-client/ host/node images fail to build. Keep a byte-identical copy inside the crate, written and verified automatically by the existing snapshot/lock tooling so the two sources cannot silently drift.
This reverts commit 941e15a.
The kona-hardforks build.rs walks ancestors of CARGO_MANIFEST_DIR to find
op-core/nuts/bundles/ during compilation. The kona-{client,host,node}
images scope their Docker context to rust/, so the ancestor walk can't
reach op-core/ and the images fail to build.
Pass op-core/nuts/bundles as an additional named BuildKit context
(nuts-bundles) and copy it into /workspace/op-core/nuts/bundles so the
ancestor walk succeeds. Keeps the primary rust/ context small and avoids
mirroring the bundle JSON into the crate tree.
caf98bb to
815bf97
Compare
added 4 commits
April 21, 2026 14:45
Iterate forks.From(forks.Karst) with a NoError assertion on derive.UpgradeTransactions rather than silently skipping forks whose bundle fails to load, so a broken bundle surfaces as a test failure. Also assert every tx in the activation block has a successful receipt so a reverted upgrade tx can't hide behind the byte-equality check.
The Hardfork impl for each NUT-bundle-backed fork is identical boilerplate (decode, EIP-2718 encode, sum gas). Move that pattern into a single internal macro so adding future forks is a one-liner next to the build-script-generated constructor.
Split parsing + codegen into build_helpers.rs, included via #[path] from both the build script and a new integration test. Use anyhow to carry error context up to a single panic in main. The integration test runs the generator on a fixture JSON and asserts the exact Rust source output, so codegen changes surface as a test failure rather than a downstream compile error.
Follows the per-fork test convention from ecotone/fjord/isthmus/holocene. Asserts the EIP-1967 implementation slot of representative predeploy proxies (L1Block, GasPriceOracle) changes across Karst activation — a Karst-specific smoke test that the bundle's proxy upgrades took effect. Not generalized into the NUT bundle activation test because it does not hold for future forks that may not upgrade proxies.
sebastianst
requested changes
Apr 22, 2026
added 2 commits
April 22, 2026 14:46
Share the initialization between the next/prev maps and replace the manual forks.All index walk in nut_bundle_activation_test.go with forks.Prev(fork). Keeps neighbor-navigation centralized in the forks package rather than re-derived at call sites.
The generic activation test was missing the core RunFaultProofProgram call (preceded by BatchMineAndSync to advance the safe head), so it only exercised the sequencer, not the proof pipeline it lives under actions/proofs/ to validate. Fold the Karst-specific impl-slot assertions back in via a switch on fork name, establishing the pattern for future forks to register their own post-activation checks alongside the universal ones. Delete karst_fork_test.go.
sebastianst
reviewed
Apr 23, 2026
0xniha
reviewed
Apr 23, 2026
Use RollupCfg.IsActivationBlockForFork instead of the unguarded IsActivationBlock(time-blockTime, time) — the helper avoids a uint64 underflow when actHeader.Time < blockTime. Assert the safe head lands exactly on the activation block rather than just past it; BatchMineAndSync adds no new L2 blocks, so equality is the right invariant.
added 4 commits
April 23, 2026 16:25
Table-driven coverage of edge cases (first, middle, last, unknown) plus a NextPrev/PrevNext inverse check that guards against the two maps drifting out of sync.
Generated bundle constructors now wrap construction in a function-scoped once_cell::sync::OnceCell and return &'static NutBundle. The first call allocates and stores the bundle; subsequent calls return a cached reference. Activation-path calls to txs() and upgrade_gas() no longer reallocate on each invocation. Consumers are unchanged — method calls auto-deref through the reference.
cargo fmt -- collapses a few multi-line statements onto one line per the use_small_heuristics = "Max" rustfmt.toml setting. cargo clippy -- replaces a match-on-Option in the bundle codegen with Option::map_or_else per the option_if_let_else lint.
The cannon-repro.dockerfile's client-build stage runs cargo build on the kona workspace, which triggers the kona-hardforks build script. That script walks ancestors of CARGO_MANIFEST_DIR looking for op-core/ and panicked because the context only contained kona/. Pull in op-core/nuts/bundles from the existing 'monorepo' named context so the ancestor walk succeeds — same pattern as the kona-node/host/client image fix.
added 2 commits
April 24, 2026 16:29
- stateful.rs: collapse the u64::from_be_bytes call onto one line per nightly rustfmt's use_small_heuristics = "Max" setting. Introduced by the original Karst upgrade_gas change; caught by rust-fmt CI. - nut_bundle_activation_test.go: use bigs.Uint64Strict(bigInt) instead of bigInt.Uint64() per the repo's bigint custom golangci-lint rule.
sync::OnceCell with the critical-section feature requires an impl of
_critical_section_1_0_{acquire,release} to be linked in, which the
MIPS64 cannon and RISC-V asterisc fault-proof VM targets don't provide.
This broke kona-client on those targets.
Switch the generator to emit once_cell::race::OnceBox, which uses a
single AtomicPtr for the cache slot — lock-free and requires no
critical-section impl. The NutBundle is heap-allocated via Box on first
call and then cached as &'static NutBundle for all subsequent calls.
Enables the `race` feature on once_cell.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Wires Karst NUT bundle execution into kona-node's payload derivation, matching op-node's behavior.
kona-hardforksgets abuild.rsthat readsop-core/nuts/bundles/karst_nut_bundle.jsonat compile time and emits Rust code constructing theNutBundle— keeps the crateno_stdand serde-free at runtime.Hardforktrait growsupgrade_gas(); the stateful attributes builder adds that gas to the block gas limit when Karst activates, so upgrade transactions have headroom.forks.rsupdated fromlen() == 0tolen() == 32to reflect the populated bundle.TestActivationBlockNUTBundleinop-e2e/actions/proofs/verifies activation block contents generically: discovery runs throughforks.All+derive.UpgradeTransactions, so any future fork that ships a NUT bundle is covered without test changes.Test plan
cargo nextest runinrust/kona— 119 passedtest_karst_upgrade_txsasserts 32 transactionstest_karst_upgrade_gasasserts 51_600_000 gasTestActivationBlockNUTBundle/karstcompiles + vets clean locally (full run needs forge artifacts — CI)Closes #20239
Closes #20144